package com.zjk.toolkit.governance.service.impl;

import com.netflix.hystrix.*;
import com.zjk.toolkit.governance.annotations.DoHystrix;
import com.zjk.toolkit.governance.service.IGovernanceService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class HystrixServiceImpl extends HystrixCommand<Object> implements IGovernanceService {

    private static final Logger log = LoggerFactory.getLogger(HystrixServiceImpl.class);

    private ProceedingJoinPoint joinPoint;
    private Method method;

    public HystrixServiceImpl(int timeout) {
        super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GovernGroup"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("GovernKey"))
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GovernThreadPool"))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionTimeoutInMilliseconds(timeout)
                        .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD))
                .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10))
        );
    }

    @Override
    public Object access(ProceedingJoinPoint joinPoint, Method method, Annotation annotation, Object[] args) {
        this.joinPoint = joinPoint;
        this.method = method;
        DoHystrix doHystrix = (DoHystrix) annotation;
        // 设置熔断超时时间
        Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GovernGroup"))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionTimeoutInMilliseconds(doHystrix.timeout()));

        return this.execute();
    }

    @Override
    protected Object run() throws Exception {
        try {
            return joinPoint.proceed();
        } catch (Throwable e) {
            log.error("{}执行失败", method.getName(), e);
            return null;
        }
    }
}
